﻿using CK.Sprite.CrossCutting;
using CK.Sprite.Framework;
using CK.Sprite.ThirdContract;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace CK.Sprite.Form.Core
{
    /*
     微服务如果是本地调用，且事物执行，则将unitofwork信息传递到微服务
     规则定义如下：
        如果点击按钮，执行：方法1;方法2 事物执行：方法3;方法4;方法5 执行：更新文本框样式...
         */

    public class RuntimeService : DomainService
    {
        private readonly SpriteObjectLocalCache _objectLocalCache;
        private readonly ObjectMethodLocalCache _methodLocalCache;

        public RedisCache _redisCache => (RedisCache)LazyGetRequiredService(ref redisCache);
        private IDistributedCache redisCache;

        public IWorkflowThirdService _workflowThirdService => LazyGetRequiredService(ref workflowThirdService);
        private IWorkflowThirdService workflowThirdService;

        public IThirdService _thirdService => LazyGetRequiredService(ref thirdService);
        private IThirdService thirdService;

        public RuntimeService(SpriteObjectLocalCache objectLocalCache,
            ObjectMethodLocalCache methodLocalCache)
        {
            _objectLocalCache = objectLocalCache;
            _methodLocalCache = methodLocalCache;
        }

        public async Task<JArray> CallRuntimeMethod(JObject paramObject)
        {
            CheckRuntimeMethods(paramObject, out string applicationCode, out bool isTransaction);
            var methods = paramObject["methods"].Children();
            Dictionary<EMethodResultRemoteType, List<JToken>> dictResultRemoteTypes = new Dictionary<EMethodResultRemoteType, List<JToken>>();
            dictResultRemoteTypes.Add(EMethodResultRemoteType.Get, new List<JToken>());
            dictResultRemoteTypes.Add(EMethodResultRemoteType.List, new List<JToken>());
            dictResultRemoteTypes.Add(EMethodResultRemoteType.PageList, new List<JToken>());
            JArray result;
            if (isTransaction)
            {
                var businessConfig = await TenantConfigStore.FindAsync(applicationCode, _serviceProvider.GetService<ICurrentTenant>().TenantCode);
                result = await _serviceProvider.DoDapperServiceAsync<JArray>(businessConfig, async (unitOfWork) =>
                {
                    return await DoRuntimeMethodAsync(methods, applicationCode, unitOfWork, businessConfig, dictResultRemoteTypes);
                });
            }
            else
            {
                result = await DoRuntimeMethodAsync(methods, applicationCode, null, null, dictResultRemoteTypes);
            }

            // 给特殊字段赋值移到事务之外执行
            foreach(var dictResultRemoteType in dictResultRemoteTypes)
            {
                if(dictResultRemoteType.Key == EMethodResultRemoteType.Get)
                {
                    foreach(var method in dictResultRemoteType.Value)
                    {
                        var findResult = result.FirstOrDefault(r => r["ruleId"].ToString() == method["ruleId"].ToString());
                        await MakeUserInfos(method, findResult["result"] as JObject);
                    }
                }

                if (dictResultRemoteType.Key == EMethodResultRemoteType.List)
                {
                    foreach (var method in dictResultRemoteType.Value)
                    {
                        var findResult = result.FirstOrDefault(r => r["ruleId"].ToString() == method["ruleId"].ToString());
                        await MakeArrayUserInfos(method, findResult["result"] as JArray);
                        await MakeArrayRemoteInfos(method, findResult["result"] as JArray);
                        await MakeArrayWorkflowInfos(method, findResult["result"] as JArray);
                    }
                }

                if (dictResultRemoteType.Key == EMethodResultRemoteType.PageList)
                {
                    foreach (var method in dictResultRemoteType.Value)
                    {
                        var findResult = result.FirstOrDefault(r => r["ruleId"].ToString() == method["ruleId"].ToString());
                        await MakeArrayUserInfos(method, findResult["result"]["items"] as JArray);
                        await MakeArrayRemoteInfos(method, findResult["result"]["items"] as JArray);
                        await MakeArrayWorkflowInfos(method, findResult["result"]["items"] as JArray);
                    }
                }
            }

            return result;
        }

        #region 远程控件调用

        public async Task<List<ValueName>> DoGetRemoteSelectCall(string applicationCode, string objectName, string filter, bool isAll)
        {
            if (string.IsNullOrEmpty(applicationCode))
            {
                applicationCode = "Default";
            }

            var spriteObjectDto = _objectLocalCache.GetAll(applicationCode).FirstOrDefault(r => r.Name == objectName);
            if (spriteObjectDto == null)
            {
                throw new SpriteException("未找到实体对象信息");
            }

            if (string.IsNullOrEmpty(spriteObjectDto.RemoteSelect))
            {
                throw new SpriteException("请设置默认远程调用信息");
            }
            var remoteSelectInfo = JsonConvert.DeserializeObject<RemoteSelectInfo>(spriteObjectDto.RemoteSelect);

            var businessConfig = await TenantConfigStore.FindAsync(applicationCode, _serviceProvider.GetService<ICurrentTenant>().TenantCode);
            var arryaResults = await _serviceProvider.DoDapperServiceAsync(businessConfig, async (unitOfWork) =>
            {
                var runtimeRepository = ConnectionFactory.GetConnectionProvider(businessConfig.ConnectionType).GetRepository<IRuntimeRepository>(unitOfWork);
                return await runtimeRepository.DoGetRemoteSelectCall(spriteObjectDto, filter, isAll);
            });

            List<ValueName> results = new List<ValueName>();

            foreach (var arryaResult in arryaResults)
            {
                var dictScriptParams = new Dictionary<string, object>();
                dictScriptParams.Add("obj", arryaResult);
                results.Add(new ValueName()
                {
                    value = arryaResult["id"].ToString(),
                    name = JavascriptUtil.Execute<string>(remoteSelectInfo.script, dictScriptParams)
                });
            }

            return results;
        }

        public async Task<List<ValueName>> DoGetByIds(string applicationCode, string objectName, string ids, string script)
        {
            if (string.IsNullOrEmpty(applicationCode))
            {
                applicationCode = "Default";
            }

            var spriteObjectDto = _objectLocalCache.GetAll(applicationCode).FirstOrDefault(r => r.Name == objectName);
            if (spriteObjectDto == null)
            {
                throw new SpriteException("未找到实体对象信息");
            }

            var businessConfig = await TenantConfigStore.FindAsync(applicationCode, _serviceProvider.GetService<ICurrentTenant>().TenantCode);
            var arryaResults = await _serviceProvider.DoDapperServiceAsync(businessConfig, async (unitOfWork) =>
            {
                var runtimeRepository = ConnectionFactory.GetConnectionProvider(businessConfig.ConnectionType).GetRepository<IRuntimeRepository>(unitOfWork);
                return await runtimeRepository.DoGetByIds(spriteObjectDto, ids);
            });

            List<ValueName> results = new List<ValueName>();

            foreach (var arryaResult in arryaResults)
            {
                var dictScriptParams = new Dictionary<string, object>();
                dictScriptParams.Add("obj", arryaResult);
                results.Add(new ValueName()
                {
                    value = arryaResult["id"].ToString(),
                    name = JavascriptUtil.Execute<string>(script, dictScriptParams)
                });
            }

            return results;
        }

        public async Task<List<ValueName>> DoGetUserByIds(string ids, string script)
        {
            if (!string.IsNullOrEmpty(ids))
            {
                var listIds = ids.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                var users = await _thirdService.GetSpriteUsersByIds(listIds);
                List<ValueName> results = new List<ValueName>();
                foreach (var user in users)
                {
                    var dictScriptParams = new Dictionary<string, object>();
                    dictScriptParams.Add("obj", user);
                    results.Add(new ValueName()
                    {
                        value = user.Id,
                        name = string.IsNullOrEmpty(script) ? $"{user.Name}({user.UserName})" : JavascriptUtil.Execute<string>(script, dictScriptParams)
                    });
                }

                return results;
            }
            return new List<ValueName>();
        }

        #endregion

        #region 导入Excel相关

        public async Task ImportExcel(string applicationCode, JArray importJArray, JArray updateJArray, SpriteObjectDto spriteObjectDto)
        {
            if (string.IsNullOrEmpty(applicationCode))
            {
                applicationCode = "Default";
            }
            var businessConfig = await TenantConfigStore.FindAsync(applicationCode, _serviceProvider.GetService<ICurrentTenant>().TenantCode);
            await _serviceProvider.DoDapperServiceAsync(businessConfig, async (unitOfWork) =>
            {
                var runtimeRepository = ConnectionFactory.GetConnectionProvider(businessConfig.ConnectionType).GetRepository<IRuntimeRepository>(unitOfWork);
                await runtimeRepository.DoBatchCreateMethodAsync(spriteObjectDto, importJArray);
                if (updateJArray != null && updateJArray.Count > 0)
                {
                    await runtimeRepository.DoBatchUpdateMethodAsync(spriteObjectDto, updateJArray);
                }
            });
        }

        public async Task<JObject> DoGetUniqInfos(string applicationCode, SpriteObjectDto spriteObjectDto, string uniqFieldInfo, List<string> uniqValues)
        {
            if (string.IsNullOrEmpty(applicationCode))
            {
                applicationCode = "Default";
            }
            var businessConfig = await TenantConfigStore.FindAsync(applicationCode, _serviceProvider.GetService<ICurrentTenant>().TenantCode);
            return await _serviceProvider.DoDapperServiceAsync(businessConfig, async (unitOfWork) =>
            {
                var runtimeRepository = ConnectionFactory.GetConnectionProvider(businessConfig.ConnectionType).GetRepository<IRuntimeRepository>(unitOfWork);
                return await runtimeRepository.DoGetUniqInfos(spriteObjectDto, uniqFieldInfo, uniqValues);
            });
        }


        #endregion

        private async Task<JArray> DoRuntimeMethodAsync(JEnumerable<JToken> methods, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, Dictionary<EMethodResultRemoteType, List<JToken>> dictResultRemoteTypes)
        {
            JArray jResult = new JArray();
            foreach (var method in methods)
            {
                var tempStrMethodId = method["methodId"].ToString();
                if (tempStrMethodId == SpriteObjectConsts.DefaultCreateOrUpdateMethodName)
                {
                    if (method["datas"]["paramValues"]["id"] == null || method["datas"]["paramValues"]["id"].ToString() == "")
                    {
                        method["methodId"] = SpriteObjectConsts.DefaultCreateMethodName;
                    }
                    else
                    {
                        method["methodId"] = SpriteObjectConsts.DefaultUpdateMethodName;
                    }
                }

                TrySetServerParams(method as JObject, jResult);
                var strMethodId = method["methodId"].ToString();
                Guid.TryParse(strMethodId, out var methodId);
                var objectName = method["objectName"].ToString();
                var spriteObjectDto = _objectLocalCache.GetAll(applicationCode).FirstOrDefault(r => r.Name == objectName);
                if (spriteObjectDto == null)
                {
                    throw new SpriteException($"未找到{objectName}数据库对象名称");
                }

                if (methodId == default) // 不是Guid，则根据传入的名称执行默认Sql方法
                {
                    await DoDefaultSqlMethod(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto, jResult);
                    switch (strMethodId) // 默认方法直接存储名称，否则存储方法Guid
                    {
                        case SpriteObjectConsts.DefaultGetMethodName:
                        case SpriteObjectConsts.DefaultGetWhereMethodName:
                            dictResultRemoteTypes[EMethodResultRemoteType.Get].Add(method);
                            break;
                        case SpriteObjectConsts.DefaultListMethodName:
                        case SpriteObjectConsts.DefaultListWhereMethodName:
                        case SpriteObjectConsts.MultiListWhereMethodName:
                        //case SpriteObjectConsts.DefaultTreeListWhereMethodName:
                            dictResultRemoteTypes[EMethodResultRemoteType.List].Add(method);
                            break;
                        case SpriteObjectConsts.DefaultPageListMethodName:
                        case SpriteObjectConsts.MultiPageListMethodName:
                            dictResultRemoteTypes[EMethodResultRemoteType.PageList].Add(method);
                            break;
                    }
                }
                else
                {
                    var methodInfo = _methodLocalCache.GetAll(applicationCode).FirstOrDefault(r => r.Id == methodId);
                    if (methodInfo == null)
                    {
                        throw new SpriteException($"未找到{objectName}对应的方法");
                    }
                    var ruleId = method["ruleId"];
                    switch (methodInfo.MethodExeType)
                    {
                        case EMethodExeType.Sql:
                            var sqlExecResult = await DoSqlMethodAsync(method, applicationCode, unitOfWork, tenantConfig, methodInfo.MethodType, methodInfo.MethodExeContent);
                            var resultSql = new JObject();
                            resultSql.Add("result", sqlExecResult);
                            resultSql.Add("ruleId", ruleId);
                            jResult.Add(resultSql);
                            if (methodInfo.MethodType == EMethodType.List)
                            {
                                dictResultRemoteTypes[EMethodResultRemoteType.List].Add(method);
                            }
                            else if (methodInfo.MethodType == EMethodType.PageList)
                            {
                                dictResultRemoteTypes[EMethodResultRemoteType.PageList].Add(method);
                            }
                            else if (methodInfo.MethodType == EMethodType.Get)
                            {
                                dictResultRemoteTypes[EMethodResultRemoteType.Get].Add(method);
                            }
                            break;
                        case EMethodExeType.反射:
                            var businessExecutor = ServiceLocator.ServiceProvider.GetService(Type.GetType(methodInfo.MethodExeContent)) as IBusinessExec;
                            JObject objectParams = new JObject();
                            objectParams["applicationCode"] = applicationCode;
                            objectParams["tenantCode"] = tenantConfig.TenantCode;
                            objectParams["params"] = method["datas"];
                            objectParams["objectName"] = method["objectName"];
                            var execResult = await businessExecutor.ExecBusinessMethod(objectParams);
                            var result = new JObject();
                            result.Add("result", execResult);
                            result.Add("ruleId", ruleId);
                            jResult.Add(result);
                            if (methodInfo.MethodType == EMethodType.List)
                            {
                                dictResultRemoteTypes[EMethodResultRemoteType.List].Add(method);
                            }
                            else if (methodInfo.MethodType == EMethodType.PageList)
                            {
                                dictResultRemoteTypes[EMethodResultRemoteType.PageList].Add(method);
                            }
                            else if (methodInfo.MethodType == EMethodType.Get)
                            {
                                dictResultRemoteTypes[EMethodResultRemoteType.Get].Add(method);
                            }
                            break;
                        case EMethodExeType.微服务:
                            break;
                        default:
                            break;
                    }
                }
            }

            return jResult;
        }

        private void TrySetServerParams(JObject method, JArray results)
        {
            if (method["paramModel"] != null && method["paramModel"].ToString() == "server" && method["serverParams"] != null) // 执行服务端方法结果赋值
            {
                var serverParamInfos = method["serverParams"].ToObject<List<ServerParamInfo>>();
                foreach (var serverParamInfo in serverParamInfos)
                {
                    foreach (var result in results)
                    {
                        if (result["ruleId"] != null && result["ruleId"].ToString() == serverParamInfo.ruleId)
                        {
                            var objResult = result["result"];
                            if (!string.IsNullOrEmpty(serverParamInfo.resultFields))
                            {
                                var resultFields = serverParamInfo.resultFields.Split(':');
                                JObject tempJObject = result["result"] as JObject;
                                for (var i = 0; i < resultFields.Length; i++)
                                {
                                    if (tempJObject[resultFields[i]] == null)
                                    {
                                        objResult = null;
                                        break;
                                    }
                                    else
                                    {
                                        objResult = tempJObject[resultFields[i]];
                                    }
                                }
                            }

                            if (!string.IsNullOrEmpty(serverParamInfo.targetFields))
                            {
                                var strTtargetFields = serverParamInfo.targetFields.ToString();
                                if (strTtargetFields.Contains('#'))
                                {
                                    var splitTargetFields = strTtargetFields.Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries);
                                    var splitArrayFields = splitTargetFields[0].Split(':');
                                    JObject tempArrayJObject = method;
                                    for (var i = 0; i < splitArrayFields.Length - 1; i++)
                                    {
                                        if (tempArrayJObject[splitArrayFields[i]] == null)
                                        {
                                            tempArrayJObject.Add(splitArrayFields[i], new JObject());
                                            tempArrayJObject = tempArrayJObject[splitArrayFields[i]] as JObject;
                                        }
                                        else
                                        {
                                            tempArrayJObject = tempArrayJObject[splitArrayFields[i]] as JObject;
                                        }
                                    }
                                    var arrayDatas = tempArrayJObject[splitArrayFields.Last()] as JArray;
                                    foreach (JObject arrayData in arrayDatas)
                                    {
                                        var strServerDictFields = splitTargetFields[1].Split(':');
                                        JObject tempJObject = arrayData;
                                        for (var i = 0; i < strServerDictFields.Length - 1; i++)
                                        {
                                            if (tempJObject[strServerDictFields[i]] == null)
                                            {
                                                tempJObject.Add(strServerDictFields[i], new JObject());
                                                tempJObject = tempJObject[strServerDictFields[i]] as JObject;
                                            }
                                            else
                                            {
                                                tempJObject = tempJObject[strServerDictFields[i]] as JObject;
                                            }
                                        }
                                        if (tempJObject[strServerDictFields.Last()] != null)
                                        {
                                            tempJObject[strServerDictFields.Last()] = objResult;
                                        }
                                        else
                                        {
                                            tempJObject.Add(strServerDictFields.Last(), objResult);
                                        }
                                    }
                                }
                                else
                                {
                                    var strServerDictFields = strTtargetFields.Split(':');
                                    JObject tempJObject = method;
                                    for (var i = 0; i < strServerDictFields.Length - 1; i++)
                                    {
                                        if (tempJObject[strServerDictFields[i]] == null)
                                        {
                                            tempJObject.Add(strServerDictFields[i], new JObject());
                                            tempJObject = tempJObject[strServerDictFields[i]] as JObject;
                                        }
                                        else
                                        {
                                            tempJObject = tempJObject[strServerDictFields[i]] as JObject;
                                        }
                                    }
                                    if (tempJObject[strServerDictFields.Last()] != null)
                                    {
                                        tempJObject[strServerDictFields.Last()] = objResult;
                                    }
                                    else
                                    {
                                        tempJObject.Add(strServerDictFields.Last(), objResult);
                                    }
                                }
                            }
                            else
                            {
                                if (method["datas"] != null)
                                {
                                    method["datas"] = objResult;
                                }
                                else
                                {
                                    method.Add("datas", objResult);
                                }
                            }
                        }
                    }
                }
            }
        }

        private async Task DoDefaultSqlMethod(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto, JArray jResult)
        {
            var strMethodId = method["methodId"].ToString();
            var ruleId = method["ruleId"];
            switch (strMethodId) // 默认方法直接存储名称，否则存储方法Guid
            {
                case SpriteObjectConsts.DefaultCreateMethodName:
                    var defaultCreateResult = await DoDefaultCreateMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultCreateResult.Add("ruleId", ruleId);
                    jResult.Add(defaultCreateResult);
                    break;
                case SpriteObjectConsts.DefaultUpdateMethodName:
                    var defaultUpdateResult = await DoDefaultUpdateMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultUpdateResult.Add("ruleId", ruleId);
                    jResult.Add(defaultUpdateResult);
                    break;
                case SpriteObjectConsts.DefaultDeleteMethodName:
                    var defaultDeleteResult = await DoDefaultDeleteMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultDeleteResult.Add("ruleId", ruleId);
                    jResult.Add(defaultDeleteResult);
                    break;
                case SpriteObjectConsts.DefaultGetMethodName:
                    var defaultGetResult = await DoDefaultGetMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultGetResult.Add("ruleId", ruleId);
                    jResult.Add(defaultGetResult);
                    break;
                case SpriteObjectConsts.DefaultFact:
                    var defaultFactResult = await DoDefaultGetMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultFactResult.Add("ruleId", ruleId);
                    jResult.Add(defaultFactResult);
                    break;
                case SpriteObjectConsts.DefaultListMethodName:
                    var defaultListResult = await DoDefaultListMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultListResult.Add("ruleId", ruleId);
                    jResult.Add(defaultListResult);
                    break;
                case SpriteObjectConsts.DefaultUpdateWhereMethodName:
                    var defaultUpdateWhereResult = await DoDefaultUpdateWhereMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultUpdateWhereResult.Add("ruleId", ruleId);
                    jResult.Add(defaultUpdateWhereResult);
                    break;
                case SpriteObjectConsts.DefaultDeleteWhereMethodName:
                    var defaultDeleteWhereResult = await DoDefaultDeleteWhereMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultDeleteWhereResult.Add("ruleId", ruleId);
                    jResult.Add(defaultDeleteWhereResult);
                    break;
                case SpriteObjectConsts.DefaultGetWhereMethodName:
                    var defaultGetWhereResult = await DoDefaultGetWhereMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultGetWhereResult.Add("ruleId", ruleId);
                    jResult.Add(defaultGetWhereResult);
                    break;
                case SpriteObjectConsts.DefaultListWhereMethodName:
                    var defaultListWhereResult = await DoDefaultListWhereMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultListWhereResult.Add("ruleId", ruleId);
                    jResult.Add(defaultListWhereResult);
                    break;
                case SpriteObjectConsts.MultiListWhereMethodName:
                    var multiListWhereResult = await DoMultiListWhereMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    multiListWhereResult.Add("ruleId", ruleId);
                    jResult.Add(multiListWhereResult);
                    break;
                case SpriteObjectConsts.DefaultTreeListWhereMethodName:
                    if (!spriteObjectDto.IsTree)
                    {
                        throw new SpriteException("方法执行错误，数据表非树结构");
                    }
                    var defaultTreeListWhereResult = await DoDefaultTreeListWhereMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultTreeListWhereResult.Add("ruleId", ruleId);
                    jResult.Add(defaultTreeListWhereResult);
                    break;
                case SpriteObjectConsts.DefaultPageListMethodName:
                    var defaultPageListResult = await DoDefaultPageListMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    defaultPageListResult.Add("ruleId", ruleId);
                    jResult.Add(defaultPageListResult);
                    break;
                case SpriteObjectConsts.MultiPageListMethodName:
                    var multiPageListResult = await DoMultiPageListMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    multiPageListResult.Add("ruleId", ruleId);
                    jResult.Add(multiPageListResult);
                    break;
                case SpriteObjectConsts.BatchCreateName:
                    var batchCreateResult = await DoBatchCreateMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
                    batchCreateResult.Add("ruleId", ruleId);
                    jResult.Add(batchCreateResult);
                    break;

                case SpriteObjectConsts.Workflow_OpenWorkflowData_FormId:
                    var workflowOpenWorkflowData = await GetFormOpenWorkflowData(method, EGetWorkflowInfoType.FormId);
                    workflowOpenWorkflowData.Add("ruleId", ruleId);
                    jResult.Add(workflowOpenWorkflowData);
                    break;
                case SpriteObjectConsts.Workflow_ParentOpenWorkflowData_FormId:
                    var workflowParentOpenWorkflowData = await GetParentFormOpenWorkflowData(method, EGetWorkflowInfoType.FormId);
                    workflowParentOpenWorkflowData.Add("ruleId", ruleId);
                    jResult.Add(workflowParentOpenWorkflowData);
                    break;
                case SpriteObjectConsts.Workflow_ParentFormInfo_FormId:
                    var workflowParentFormInfo = await GetParentFormInfo(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto, EGetWorkflowInfoType.FormId);
                    workflowParentFormInfo.Add("ruleId", ruleId);
                    jResult.Add(workflowParentFormInfo);
                    break;
                case SpriteObjectConsts.Workflow_OpenWorkflowData_InstanceId:
                    var workflowOpenWorkflowData2 = await GetFormOpenWorkflowData(method, EGetWorkflowInfoType.InstanceId);
                    workflowOpenWorkflowData2.Add("ruleId", ruleId);
                    jResult.Add(workflowOpenWorkflowData2);
                    break;
                case SpriteObjectConsts.Workflow_ParentOpenWorkflowData_InstanceId:
                    var workflowParentOpenWorkflowData2 = await GetParentFormOpenWorkflowData(method, EGetWorkflowInfoType.InstanceId);
                    workflowParentOpenWorkflowData2.Add("ruleId", ruleId);
                    jResult.Add(workflowParentOpenWorkflowData2);
                    break;
                case SpriteObjectConsts.Workflow_ParentFormInfo_InstanceId:
                    var workflowParentFormInfo2 = await GetParentFormInfo(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto, EGetWorkflowInfoType.InstanceId);
                    workflowParentFormInfo2.Add("ruleId", ruleId);
                    jResult.Add(workflowParentFormInfo2);
                    break;
                case SpriteObjectConsts.FormateTimeMethodName: // 获取时间
                    var formateTimeResult = DoFormateTime(method);
                    formateTimeResult.Add("ruleId", ruleId);
                    jResult.Add(formateTimeResult);
                    break;
                case SpriteObjectConsts.CurrentUserInfoMethodName: // 当前用户
                    var currentUserResult = await DoCurrentUserInfo(method);
                    currentUserResult.Add("ruleId", ruleId);
                    jResult.Add(currentUserResult);
                    break;
                case SpriteObjectConsts.CurrentUserDeptInfoMethodName: // 获取用户部门信息
                    var currentUserDeptResult = await DoCurrentUserDeptInfoAsync(method);
                    currentUserDeptResult.Add("ruleId", ruleId);
                    jResult.Add(currentUserDeptResult);
                    break;
                case SpriteObjectConsts.UserInfoMethodName: // 特定用户，不传查询当前用户
                    var userResult = await DoUserInfoAsync(method);
                    userResult.Add("ruleId", ruleId);
                    jResult.Add(userResult);
                    break;
                case SpriteObjectConsts.UserInfoDeptMethodName: // 特定部门，不传查询当前用户部门
                    var userDeptResult = await DoUserInfoDeptAsync(method);
                    userDeptResult.Add("ruleId", ruleId);
                    jResult.Add(userDeptResult);
                    break;
                default:
                    break;
            }
        }

        #region 默认方法执行

        #region 默认其他方法
        private async Task<JObject> DoUserInfoDeptAsync(JToken method)
        {
            JToken datas = method["datas"];
            if (datas["deptId"] != null)
            {
                var dept = await _thirdService.GetSpriteDept(datas["deptId"].ToString());
                JObject result = new JObject();
                result.Add(new JProperty("result", JsonConvert.DeserializeObject(JsonConvert.SerializeObject(dept))));

                return result;
            }
            else
            {
                return await DoCurrentUserDeptInfoAsync(method);
            }
        }

        private async Task<JObject> DoUserInfoAsync(JToken method)
        {
            JToken datas = method["datas"];
            if (datas["userId"] != null)
            {
                var user = await _thirdService.GetSpriteUser(datas["userId"].ToString());
                JObject result = new JObject();
                result.Add(new JProperty("result", JsonConvert.DeserializeObject(JsonConvert.SerializeObject(user))));

                return result;
            }
            else
            {
                return await DoCurrentUserInfo(method);
            }
        }

        private async Task<JObject> DoCurrentUserDeptInfoAsync(JToken method)
        {
            ICurrentUser currentUser = System.ServiceLocator.ServiceProvider.GetService<ICurrentUser>();
            JObject result = new JObject();
            var dept = await _thirdService.GetSpriteDept(currentUser.DeptId);
            result.Add(new JProperty("result", JsonConvert.DeserializeObject(JsonConvert.SerializeObject(dept))));

            return result;
        }

        private async Task<JObject> DoCurrentUserInfo(JToken method)
        {
            ICurrentUser currentUser = System.ServiceLocator.ServiceProvider.GetService<ICurrentUser>();
            JObject result = new JObject();
            result.Add(new JProperty("result", JsonConvert.DeserializeObject(JsonConvert.SerializeObject(currentUser))));

            return await Task.FromResult(result);
        }

        private JObject DoFormateTime(JToken method)
        {
            JToken datas = method["datas"];
            var formateTimeInfo = JsonConvert.DeserializeObject<FormateTimeInfo>(datas.ToString());
            var startTime = formateTimeInfo.StartTime.HasValue ? formateTimeInfo.StartTime.Value : DateTime.Now;
            var endTime = formateTimeInfo.EndTime.HasValue ? formateTimeInfo.EndTime.Value : DateTime.Now;

            CalculateTimeHelper.CalculateDateTime(formateTimeInfo.TimeType, formateTimeInfo.CalculateDate, ref startTime, ref endTime);

            JObject result = new JObject();
            JObject jResut = new JObject();
            jResut.Add(new JProperty("startTime", startTime.ToString("yyyy-MM-dd HH:mm:ss")));
            jResut.Add(new JProperty("endTime", endTime.ToString("yyyy-MM-dd HH:mm:ss")));
            
            if(formateTimeInfo.RepairTimeType.HasValue)
            {
                List<ValueName> valueNames = new List<ValueName>();

                switch (formateTimeInfo.RepairTimeType.Value)
                {
                    case ERepairTimeType.Week:
                        while (startTime < endTime)
                        {
                            valueNames.Add(new ValueName()
                            {
                                name = startTime.DayOfWeek.GetWeekName(),
                                value = startTime.ToString("yyyy-MM-dd")
                            });
                            startTime = startTime.AddDays(1);
                        }
                        break;
                    case ERepairTimeType.Day:
                        while (startTime < endTime)
                        {
                            valueNames.Add(new ValueName()
                            {
                                name = $"{startTime.Day}日",
                                value = startTime.ToString("yyyy-MM-dd")
                            });
                            startTime = startTime.AddDays(1);
                        }
                        break;
                    case ERepairTimeType.DayMonth:
                        while (startTime < endTime)
                        {
                            valueNames.Add(new ValueName()
                            {
                                name = $"{startTime.Month}月{startTime.Day}日",
                                value = startTime.ToString("yyyy-MM-dd")
                            });
                            startTime = startTime.AddDays(1);
                        }
                        break;
                    case ERepairTimeType.DayMonthYear:
                        while (startTime < endTime)
                        {
                            valueNames.Add(new ValueName()
                            {
                                name = $"{startTime.Year}年{startTime.Month}月{startTime.Day}日",
                                value = startTime.ToString("yyyy-MM-dd")
                            });
                            startTime = startTime.AddDays(1);
                        }
                        break;
                    case ERepairTimeType.Month:
                        while ((startTime.Year * 100) + startTime.Month <= (endTime.Year * 100) + endTime.Month)
                        {
                            valueNames.Add(new ValueName()
                            {
                                name = $"{startTime.Month}月",
                                value = startTime.ToString("yyyy-MM")
                            });
                            startTime = startTime.AddMonths(1);
                        }
                        break;
                    case ERepairTimeType.MonthYear:
                        while ((startTime.Year * 100) + startTime.Month <= (endTime.Year * 100) + endTime.Month)
                        {
                            valueNames.Add(new ValueName()
                            {
                                name = $"{startTime.Year}年{startTime.Month}月",
                                value = startTime.ToString("yyyy-MM")
                            });
                            startTime = startTime.AddMonths(1);
                        }
                        break;
                    case ERepairTimeType.Year:
                        while (startTime.Year <= endTime.Year)
                        {
                            valueNames.Add(new ValueName()
                            {
                                name = $"{startTime.Year}年",
                                value = startTime.ToString("yyyy")
                            });
                            startTime = startTime.AddYears(1);
                        }
                        break;
                }
                jResut.Add(new JProperty("repairDatas", JsonConvert.DeserializeObject(JsonConvert.SerializeObject(valueNames))));
            }

            result.Add(new JProperty("result", jResut));

            return result;
        }

        #endregion

        private async Task<JObject> DoDefaultMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, Func<IRuntimeRepository, JToken, Task<JObject>> func)
        {
            JToken datas = method["datas"];
            if (unitOfWork == null)
            {
                var businessConfig = await TenantConfigStore.FindAsync(applicationCode, _serviceProvider.GetService<ICurrentTenant>().TenantCode);
                return await _serviceProvider.DoDapperServiceAsync(businessConfig, async (unitOfWorkNew) =>
                {
                    var runtimeRepository = ConnectionFactory.GetConnectionProvider(tenantConfig.ConnectionType).GetRepository<IRuntimeRepository>(unitOfWorkNew);
                    var funcResult = await func(runtimeRepository, datas);
                    return funcResult;
                });
            }
            else
            {
                var runtimeRepository = ConnectionFactory.GetConnectionProvider(tenantConfig.ConnectionType).GetRepository<IRuntimeRepository>(unitOfWork);
                var funcResult = await func(runtimeRepository, datas);
                return funcResult;
            }
        }

        // 执行默认Create方法
        private async Task<JObject> DoDefaultCreateMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                return await runtimeRepository.DoDefaultCreateMethodAsync(spriteObjectDto, datas["paramValues"]?.ToObject<JObject>());
            });
        }

        // 执行默认Update方法
        private async Task<JObject> DoDefaultUpdateMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                return await runtimeRepository.DoDefaultUpdateMethodAsync(spriteObjectDto, datas["paramValues"]?.ToObject<JObject>());
            });
        }

        // 执行默认Delete方法
        private async Task<JObject> DoDefaultDeleteMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                return await runtimeRepository.DoDefaultDeleteMethodAsync(spriteObjectDto, datas["paramValues"]?.ToObject<JObject>());
            });
        }

        // 执行默认Get方法
        private async Task<JObject> DoDefaultGetMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                var result = await runtimeRepository.DoDefaultGetMethodAsync(spriteObjectDto, datas["paramValues"]?.ToObject<JObject>(), datas["sqlFields"]?.ToObject<JArray>());

                //await MakeUserInfos(method, result["result"] as JObject);

                return result;
            });
        }

        // 执行默认List方法
        private async Task<JObject> DoDefaultListMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                var result = await runtimeRepository.DoDefaultListMethodAsync(spriteObjectDto, datas["paramValues"]?.ToObject<JObject>(), datas["sqlFields"]?.ToObject<JArray>(), datas["sqlOrderBys"]);

                return result;
            });
        }

        // 执行默认Update Where方法
        private async Task<JObject> DoDefaultUpdateWhereMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                return await runtimeRepository.DoDefaultUpdateWhereMethodAsync(spriteObjectDto, datas["paramValues"]?.ToObject<JObject>(), datas["sqlWheres"]);
            });
        }

        // 执行默认Delete方法
        private async Task<JObject> DoDefaultDeleteWhereMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                return await runtimeRepository.DoDefaultDeleteWhereMethodAsync(spriteObjectDto, datas["paramValues"]?.ToObject<JObject>(), datas["sqlWheres"]);
            });
        }

        // 执行默认Get Where方法
        private async Task<JObject> DoDefaultGetWhereMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                var result = await runtimeRepository.DoDefaultGetWhereMethodAsync(spriteObjectDto, datas["paramValues"]?.ToObject<JObject>(), datas["sqlWheres"], datas["sqlFields"]?.ToObject<JArray>());
                //await MakeUserInfos(method, result["result"] as JObject);
                return result;
            });
        }

        // 执行默认List Where方法
        private async Task<JObject> DoDefaultListWhereMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                var result = await runtimeRepository.DoDefaultListWhereMethodAsync(spriteObjectDto, datas["paramValues"]?.ToObject<JObject>(), datas["sqlWheres"], datas["sqlFields"]?.ToObject<JArray>(), datas["sqlOrderBys"]);
                return result;
            });
        }

        private async Task<JObject> DoMultiListWhereMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                var dictAliasInfos = GetDictMultiInfos(datas, applicationCode);

                var result = await runtimeRepository.DoMultiListWhereMethodAsync(dictAliasInfos, datas["joinInfos"], datas["paramValues"]?.ToObject<JObject>(), datas["sqlWheres"], datas["sqlFields"]?.ToObject<JArray>(), datas["sqlOrderBys"]);
                return result;
            });
        }

        // 执行默认List Where方法
        private async Task<JObject> DoDefaultTreeListWhereMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                var queryResult = await runtimeRepository.DoDefaultListWhereMethodAsync(spriteObjectDto, datas["paramValues"]?.ToObject<JObject>(), datas["sqlWheres"], datas["sqlFields"]?.ToObject<JArray>(), datas["sqlOrderBys"]);

                await MakeArrayUserInfos(method, queryResult["result"] as JArray);
                await MakeArrayRemoteInfos(method, queryResult["result"] as JArray);
                await MakeArrayWorkflowInfos(method, queryResult["result"] as JArray);

                var queryDatas = queryResult["result"].ToObject<JArray>();
                var treeCodes = queryDatas.Select(r => r["treeCode"].ToString());
                var parentIds = new List<string>();
                foreach (var treeCode in treeCodes)
                {
                    var tempIds = treeCode.Substring(2).Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                    parentIds.AddRange(tempIds);
                }

                parentIds = parentIds.Distinct().ToList();
                parentIds = parentIds.Where(r => !queryDatas.Any(t => t["id"].ToString() == r)).ToList();

                if (parentIds.Count > 0)
                {
                    var expressSqlModel = new ExpressSqlModel()
                    {
                        SqlExpressType = ESqlExpressType.And,
                        Children = new List<ExpressSqlModel>()
                        {
                            new ExpressSqlModel()
                            {
                                Field = "Id",
                                ConditionType = EConditionType.In,
                                SqlExpressType = ESqlExpressType.Condition,
                                Value = parentIds
                            }
                        }
                    };

                    var parentQueryResult = await runtimeRepository.DoDefaultListWhereMethodAsync(spriteObjectDto, null, JObject.FromObject(expressSqlModel, ExpressSqlHelper.CreateCamelCaseJsonSerializer()), datas["sqlFields"]?.ToObject<JArray>(), null);

                    var parentQueryDatas = parentQueryResult["result"].ToObject<JArray>();
                    if (parentQueryDatas != null && parentQueryDatas.Count > 0)
                    {
                        foreach (var parentQueryData in parentQueryDatas)
                        {
                            queryDatas.Add(parentQueryData);
                        }
                    }
                }

                var resultDatas = new JArray();
                var rootDatas = queryDatas.Where(r => r["treeCode"].ToString() == "0.").ToList();
                foreach (var rootData in rootDatas)
                {
                    CreateTreeList(queryDatas, rootData as JObject);
                    CreateVueTreeInfo(rootData as JObject);
                    resultDatas.Add(rootData);
                }

                queryResult["result"] = resultDatas;

                return queryResult;
            });
        }

        private void CreateTreeList(JArray treeDatas, JObject parentData)
        {
            var childDatas = treeDatas.Where(r => r["pId"].ToString() == parentData["id"].ToString()).ToList();
            if (childDatas.Count > 0)
            {
                parentData.Add(new JProperty("children", new JArray()));
                foreach (var childData in childDatas)
                {
                    CreateTreeList(treeDatas, childData as JObject);
                    CreateVueTreeInfo(childData as JObject);
                    (parentData["children"] as JArray).Add(childData);
                }
            }
        }

        private void CreateVueTreeInfo(JObject jObject)
        {
            jObject.Add(new JProperty("key", jObject["id"]));
            jObject.Add(new JProperty("value", jObject["id"]));
        }

        // 执行通用Sql方法
        private async Task<JObject> DoSqlMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, EMethodType mehodType, string sqlMethodContent)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                var result = await runtimeRepository.DoSqlMethodAsync(mehodType, sqlMethodContent, datas["paramValues"]?.ToObject<JObject>(), datas["sqlWheres"]
                    , datas["sqlFields"]?.ToObject<JArray>(), datas["sqlOrderBys"], datas["sqlMaxResultCount"], datas["sqlSkipCount"]);
                //if(mehodType == EMethodType.List)
                //{
                //    await MakeArrayUserInfos(method, result["result"] as JArray);
                //    await MakeArrayRemoteInfos(method, result["result"] as JArray);
                //    await MakeArrayWorkflowInfos(method, result["result"] as JArray);
                //}
                //else if(mehodType == EMethodType.PageList)
                //{
                //    await MakeArrayUserInfos(method, result["result"]["items"] as JArray);
                //    await MakeArrayRemoteInfos(method, result["result"]["items"] as JArray);
                //    await MakeArrayWorkflowInfos(method, result["result"]["items"] as JArray);
                //}
                //else if(mehodType == EMethodType.Get)
                //{
                //    await MakeUserInfos(method, result["result"] as JObject);
                //}
                
                return result;
            });
        }

        // 执行默认Page List方法
        private async Task<JObject> DoDefaultPageListMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                var result = await runtimeRepository.DoDefaultPageListMethodAsync(spriteObjectDto, datas["paramValues"]?.ToObject<JObject>(), datas["sqlWheres"], datas["sqlFields"]?.ToObject<JArray>(), datas["sqlOrderBys"], datas["sqlMaxResultCount"], datas["sqlSkipCount"]);
                return result;
            });
        }

        // 执行默认Page List方法
        private async Task<JObject> DoMultiPageListMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                var dictAliasInfos = GetDictMultiInfos(datas, applicationCode);

                var result = await runtimeRepository.DoMultiPageListMethodAsync(dictAliasInfos, datas["joinInfos"], datas["paramValues"]?.ToObject<JObject>(), datas["sqlWheres"], datas["sqlFields"]?.ToObject<JArray>(), datas["sqlOrderBys"], datas["sqlMaxResultCount"], datas["sqlSkipCount"]);
                return result;
            });
        }

        private async Task<JObject> DoBatchCreateMethodAsync(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto)
        {
            return await DoDefaultMethodAsync(method, applicationCode, unitOfWork, tenantConfig, async (runtimeRepository, datas) =>
            {
                var result = await runtimeRepository.DoBatchCreateMethodAsync(spriteObjectDto, datas?.ToObject<JArray>());
                return result;
            });
        }

        private Dictionary<string, SpriteObjectDto> GetDictMultiInfos(JToken datas, string applicationCode)
        {
            // aliasInfos格式为：table1:a;table2:b，且与joinInfos需要完全对应，且与view的ObjectName一一对应，别名必须是a,b,c依此类推
            var strAliasInfos = datas["aliasInfos"].ToString();
            CommonConsts.CheckSqlInject(strAliasInfos, new List<string>() { ";" });
            var spliteAliasInfos = strAliasInfos.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
            Dictionary<string, SpriteObjectDto> dictAliasInfos = new Dictionary<string, SpriteObjectDto>();
            var spriteObjectLocalCache = ServiceLocator.ServiceProvider.GetService<SpriteObjectLocalCache>();
            var allSpriteObjectDtos = spriteObjectLocalCache.GetAll(applicationCode);
            foreach (var spliteAliasInfo in spliteAliasInfos)
            {
                var tempSplitInfo = spliteAliasInfo.Split(':');
                var findSpriteObjectDto = allSpriteObjectDtos.FirstOrDefault(r => r.Name == tempSplitInfo[0]);
                if (findSpriteObjectDto == null)
                {
                    throw new SpriteException($"未打到{spliteAliasInfo[0]}对象信息");
                }
                dictAliasInfos.Add(tempSplitInfo[1], findSpriteObjectDto);
            }

            return dictAliasInfos;
        }

        #endregion

        #region 工作流相关

        private async Task<JObject> GetFormOpenWorkflowData(JToken method, EGetWorkflowInfoType workflowInfoType)
        {
            JToken datas = method["datas"];
            var id = datas["paramValues"]["id"].ToString();
            var result = await _workflowThirdService.GetFormOpenWorkflowData(id, workflowInfoType);
            if(result == null)
            {
                throw new SpriteException("获取工作流信息失败");
            }
            return JObject.FromObject(result);
        }

        private async Task<JObject> GetParentFormOpenWorkflowData(JToken method, EGetWorkflowInfoType workflowInfoType)
        {
            JToken datas = method["datas"];
            var id = datas["paramValues"]["id"].ToString();
            var result = await _workflowThirdService.GetParentFormOpenWorkflowData(id, workflowInfoType);
            if (result == null)
            {
                throw new SpriteException("获取工作流信息失败");
            }
            return JObject.FromObject(result);
        }

        private async Task<JObject> GetParentFormInfo(JToken method, string applicationCode, IUnitOfWork unitOfWork, TenantConfig tenantConfig, SpriteObjectDto spriteObjectDto, EGetWorkflowInfoType workflowInfoType)
        {
            JToken datas = method["datas"];
            var id = datas["paramValues"]["id"].ToString();
            var result = await _workflowThirdService.GetParentFormId(id, workflowInfoType);
            if (string.IsNullOrEmpty(result))
            {
                throw new SpriteException("获取工作流信息失败");
            }
            datas["paramValues"]["id"] = result;
            return await DoDefaultGetMethodAsync(method, applicationCode, unitOfWork, tenantConfig, spriteObjectDto);
        }

        #endregion

        #region 获取用户信息并添加到返回实体

        private async Task MakeArrayUserInfos(JToken method, JArray arrayInfos)
        {
            if (method["userFields"] != null && !string.IsNullOrEmpty(method["userFields"].ToString()) && arrayInfos != null)
            {
                List<string> userIds = new List<string>();
                var userFields = method["userFields"].ToString().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var userField in userFields)
                {
                    if (arrayInfos.Count > 0)
                    {
                        foreach (var arrayInfo in arrayInfos)
                        {
                            if (arrayInfo[userField] != null)
                            {
                                userIds.AddRange(arrayInfo[userField].ToString().Split(new char[] { ';'}));
                            }
                        }
                    }
                }

                userIds = userIds.Distinct().ToList();
                var userInfos = await _thirdService.GetSpriteUsersByIds(userIds);
                foreach (var userField in userFields)
                {
                    if (arrayInfos.Count > 0)
                    {
                        foreach (var arrayInfo in arrayInfos)
                        {
                            if (arrayInfo[userField] != null)
                            {
                                (arrayInfo as JObject).Add(new JProperty($"{userField}_UserName", string.Join(";", userInfos.Where(r => arrayInfo[userField].ToString().Contains(r.Id)).Select(r=>r.Name))));
                            }
                        }
                    }
                }
            }
        }

        private async Task MakeArrayRemoteInfos(JToken method, JArray arrayInfos)
        {
            if (method["remoteFieldInfos"] != null && !string.IsNullOrEmpty(method["remoteFieldInfos"].ToString()) && arrayInfos != null)
            {
                List<RemoteFieldInfo> remoteFieldInfos = JsonConvert.DeserializeObject<List<RemoteFieldInfo>>(method["remoteFieldInfos"].ToString());
                foreach (var remoteFieldInfo in remoteFieldInfos)
                {
                    StringBuilder sbRemoteIds = new StringBuilder();
                    foreach (JToken arrayInfo in arrayInfos)
                    {
                        if (arrayInfo[remoteFieldInfo.field] != null)
                        {
                            sbRemoteIds.Append($"{arrayInfo[remoteFieldInfo.field]};");
                        }
                    }
                    if (sbRemoteIds.Length > 0)
                    {
                        var ids = sbRemoteIds.ToString();
                        var remoteInfos = await DoGetByIds(remoteFieldInfo.applicationCode, remoteFieldInfo.objectName, ids, remoteFieldInfo.script);

                        foreach (var arrayInfo in arrayInfos)
                        {
                            if (arrayInfo[remoteFieldInfo.field] != null)
                            {
                                var remoteFieldIds = arrayInfo[remoteFieldInfo.field].ToString().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                                List<string> remoteFieldNames = new List<string>();
                                foreach (var remoteFieldId in remoteFieldIds)
                                {
                                    var remoteInfo = remoteInfos.FirstOrDefault(r => r.value == remoteFieldId);
                                    if (remoteInfo != null)
                                    {
                                        remoteFieldNames.Add(remoteInfo.name);
                                    }
                                }
                                if (remoteFieldNames.Count > 0)
                                {
                                    (arrayInfo as JObject).Add(new JProperty($"{remoteFieldInfo.field}_Name", string.Join(";", remoteFieldNames)));
                                }
                                else
                                {
                                    (arrayInfo as JObject).Add(new JProperty($"{remoteFieldInfo.field}_Name", null));
                                }
                            }
                            else
                            {
                                (arrayInfo as JObject).Add(new JProperty($"{remoteFieldInfo.field}_Name", null));
                            }
                        }
                    }
                }
            }
        }

        private async Task MakeArrayWorkflowInfos(JToken method, JArray arrayInfos)
        {
            if (method["instanceIdField"] != null && !string.IsNullOrEmpty(method["instanceIdField"].ToString()) && arrayInfos != null)
            {
                var instanceField = method["instanceIdField"].ToString();

                List<string> instanceIds = new List<string>();
                foreach (JObject arrayInfo in arrayInfos)
                {
                    if (arrayInfo.ContainsKey(instanceField))
                    {
                        instanceIds.Add(arrayInfo[instanceField].ToString());
                    }
                }

                var formWorkflowInfos = await _workflowThirdService.GetFormWorkflowInfos(instanceIds);

                foreach (JObject arrayInfo in arrayInfos)
                {
                    var instanceId = arrayInfo[instanceField].ToString();
                    var formWorkflowInfo = formWorkflowInfos.FirstOrDefault(r => r.InstanceId == instanceId);
                    if (formWorkflowInfo != null)
                    {
                        arrayInfo.Add(new JProperty("flow_InstanceId", formWorkflowInfo.InstanceId));
                        arrayInfo.Add(new JProperty("flow_Status", formWorkflowInfo.Status));
                        arrayInfo.Add(new JProperty("flow_CurrentActivities", formWorkflowInfo.CurrentActivities));
                        arrayInfo.Add(new JProperty("flow_InstanceName", formWorkflowInfo.InstanceName));
                        arrayInfo.Add(new JProperty("flow_StartedAt", formWorkflowInfo.StartedAt.HasValue ? formWorkflowInfo.StartedAt.Value.ToString("yyyy-MM-dd HH:mm") : ""));
                        arrayInfo.Add(new JProperty("flow_FinishedAt", formWorkflowInfo.FinishedAt.HasValue ? formWorkflowInfo.FinishedAt.Value.ToString("yyyy-MM-dd HH:mm") : ""));
                    }
                }
            }
        }

        private async Task MakeUserInfos(JToken method, JObject data)
        {
            if (method["userFields"] != null && !string.IsNullOrEmpty(method["userFields"].ToString()))
            {
                List<string> userIds = new List<string>();
                var userFields = method["userFields"].ToString().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var userField in userFields)
                {
                    if (data[userField] != null)
                    {
                        userIds.AddRange(data[userField].ToString().Split(new char[] { ';' }));
                    }
                }

                userIds = userIds.Distinct().ToList();
                var userInfos = await _thirdService.GetSpriteUsersByIds(userIds);
                foreach (var userField in userFields)
                {
                    if (data[userField] != null)
                    {
                        data.Add(new JProperty($"{userField}_UserName", string.Join(";", userInfos.Where(r => data[userField].ToString().Contains(r.Id)).Select(r=>r.Name))));
                    }
                }
            }
        }

        #endregion

        #region Core

        //private async Task<string> CreateSerialNumber()
        //{
        //    var dataBase = _redisCache.GetDatabaseAsync().Result;
        //}

        #endregion

        private void CheckRuntimeMethods(JObject paramObject, out string applicationCode, out bool isTransaction)
        {
            if (!paramObject.ContainsKey("applicationCode"))
            {
                paramObject.Add("applicationCode", "Default");
                //throw new SpriteException("方法调用未传递应用编码");
            }

            if (!paramObject.ContainsKey("methods"))
            {
                throw new SpriteException("方法调用未传递调用方法");
            }

            applicationCode = paramObject["applicationCode"].ToString();

            isTransaction = true;
            if (paramObject.ContainsKey("isTransaction"))
            {
                isTransaction = paramObject["isTransaction"].Value<bool>();
            }
        }
    }

    internal class ServerParamInfo
    {
        /// <summary>
        /// 如果为空，直接替换datas；如果包含#，则表示列表替换，#前表示哪个参数为列表，#后为替换的Id参数，如果不包含#，表示单个替换
        /// </summary>
        public string targetFields { get; set; }
        public string ruleId { get; set; }
        public string resultFields { get; set; }
    }

    internal class RemoteFieldInfo
    {
        public string applicationCode { get; set; }
        public string objectName { get; set; }
        public string field { get; set; }
        public string script { get; set; }
    }

    internal enum EMethodResultRemoteType
    {
        Get = 1,
        List = 2,
        PageList = 3
    }

    /// <summary>
    /// 补全时间枚举数据
    /// </summary>
    internal enum ERepairTimeType
    {
        Week = 1,
        Day = 2,
        DayMonth = 3,
        DayMonthYear = 4,
        Month = 5,
        MonthYear = 6,
        Year = 7
    }

    internal class FormateTimeInfo
    {
        public ETimeType TimeType { get; set; }

        /// <summary>
        /// 计算的所在日期，为空，则计算当天
        /// </summary>
        public DateTime? CalculateDate { get; set; }

        /// <summary>
        /// 自定义时填写
        /// </summary>
        public DateTime? StartTime { get; set; }

        /// <summary>
        /// 自定义时填写
        /// </summary>
        public DateTime? EndTime { get; set; }

        /// <summary>
        /// 补全时间枚举
        /// </summary>
        public ERepairTimeType? RepairTimeType { get; set; }
    }
}
